package com.guazai.apigateway.exception;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.guazai.apigateway.common.BaseResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebExceptionHandler;
import reactor.core.publisher.Mono;

/**
 * 全局异常处理器
 *
 * @author guazai
 */
@Configuration
@Slf4j
@Order(-1)
public class GlobalExceptionHandler implements WebExceptionHandler {

    private final ObjectMapper objectMapper = new ObjectMapper();


    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        //获得response
        ServerHttpResponse response = exchange.getResponse();
        //如果response已提交说明已处理，则返回Mono.error()
        if (response.isCommitted()) {
            return Mono.error(ex);
        }
        //在响应头里设置response返回值类型为json
        HttpHeaders headers = response.getHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        //获得响应数据
        BaseResponse<String> error = new BaseResponse<>(HttpStatus.FORBIDDEN.value(), ex.getMessage());
        log.error("网关异常：{}", error);
        try {
            //将响应数据转成byte数组
            byte[] bytes = objectMapper.writeValueAsBytes(error);
            //获得dataBuffer
            DataBufferFactory bufferFactory = response.bufferFactory();
            //用dataBuffer包装数据
            DataBuffer wrap = bufferFactory.wrap(bytes);
            //刷新缓存
            return response.writeWith(Mono.just(wrap));
        } catch (JsonProcessingException e) {
            log.error("网关序列化异常：{}", e.getMessage());
            return Mono.error(e);
        }
    }
}
